`timescale 1ns/1ps
`default_nettype none

/* NOTE:
* - 本模负责进行色度调整
* - 每3个周期完成一次计算
* - 依次计算RGB，每个周期读入相应系数
* - 输入/输出RGB为16bit无符号数
* - 系数为16bit无符号数，15bit小数位
*/

module color_adjust (
    // system signal
    input  wire         I_sclk,
    input  wire         I_rst_n,
    // adjust enable
    input  wire         I_adjust_en,
    // input pixel
    input  wire         I_data_en,
    input  wire [15:0]  I_r_in,
    input  wire [15:0]  I_g_in,
    input  wire [15:0]  I_b_in,
    // coefficient
    output wire         O_coe_ack,
    input  wire [15:0]  I_coe_r,
    input  wire [15:0]  I_coe_g,
    input  wire [15:0]  I_coe_b,
    // result
    output wire         O_valid,
    output wire [15:0]  O_r_out,
    output wire [15:0]  O_g_out,
    output wire [15:0]  O_b_out
);
//------------------------Parameter----------------------

//------------------------Local signal-------------------
reg  [5:0]  valid_sr;
reg  [15:0] r_buf;
reg  [15:0] g_buf;
reg  [15:0] b_buf;
reg  [31:0] p0;
reg  [31:0] p1;
reg  [31:0] p2;
reg  [33:0] sum;
reg  [15:0] r_out;
reg  [15:0] g_out;
reg  [15:0] b_out;

//------------------------Instantiation------------------

//------------------------Body---------------------------
// NOTE:
// 调整系数是预读取好的，行为类似show ahead fifo
// O_coe_ack为高表示当前系数已使用，切换下一个系数
assign O_coe_ack = |valid_sr[2:0];

assign O_valid = I_adjust_en ? valid_sr[5] : valid_sr[0];
assign O_r_out = r_out;
assign O_g_out = g_out;
assign O_b_out = b_out;

// valid_sr
always @(posedge I_sclk or negedge I_rst_n) begin
    if (~I_rst_n)
        valid_sr <= 1'b0;
    else
        valid_sr <= {valid_sr[4:0], I_data_en};
end

// r_buf, g_buf, b_buf
always @(posedge I_sclk) begin
    if (I_data_en) begin
        r_buf <= I_r_in;
        g_buf <= I_g_in;
        b_buf <= I_b_in;
    end
end

// p0, p1, p2
always @(posedge I_sclk) begin
    p0 <= r_buf * I_coe_r;
    p1 <= g_buf * I_coe_g;
    p2 <= b_buf * I_coe_b;
end

// sum
always @(posedge I_sclk) begin
    sum <= p0 + p1 + p2;
end

// r_out
always @(posedge I_sclk) begin
    if (~I_adjust_en)
        r_out <= I_r_in;
    else if (valid_sr[2]) begin
        if (sum[33:31] != 1'b0)
            r_out <= 16'hffff;
        else
            r_out <= sum[30:15];
    end
end

// g_out
always @(posedge I_sclk) begin
    if (~I_adjust_en)
        g_out <= I_g_in;
    else if (valid_sr[3]) begin
        if (sum[33:31] != 1'b0)
            g_out <= 16'hffff;
        else
            g_out <= sum[30:15];
    end
end

// b_out
always @(posedge I_sclk) begin
    if (~I_adjust_en)
        b_out <= I_b_in;
    else if (valid_sr[4]) begin
        if (sum[33:31] != 1'b0)
            b_out <= 16'hffff;
        else
            b_out <= sum[30:15];
    end
end

endmodule

`default_nettype wire

// vim:set ts=4 sw=4 et fenc=utf-8 fdm=marker:
